home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d19 / cal14s6.arc / CALLS.PAS < prev    next >
Pascal/Delphi Source File  |  1988-12-31  |  61KB  |  2,139 lines

  1.  
  2. {$M 50000,30000,500000}  {Stack, minheap, maxheap}
  3.  
  4. {$L-}    {Don't link in ram}
  5. {$S-}    {Stack testing}
  6. {$R-}    {Range checks}
  7. {$V-}    {Relax string rules}
  8.  
  9. program callers;
  10.  
  11. uses dos, bufio, crt;
  12.  
  13.  
  14. {                 PCBoard Call Analyzer Ver. 11.7  02/19/87                }
  15. {                                                                          }
  16. {       PCBoard Call Analyzer written by Warren Lauzon of Phoenix AZ       }
  17. {                 Phoenix Techline PCBoard   602-936-3058                  }
  18. {                                                                          }
  19. {      (updated for PCBoard 11.8 and PCB ProDOOR, S.H.Smith, 09/02/87)     }
  20. {              (updated for PCBoard 12.1 S.H.Smith, 11/20/87)              }
  21.  
  22.  
  23. const
  24.    version = '14s6';
  25.    reldate = '12-31-88';
  26.    pcbversion = 'For PCBoard v14.0';
  27.  
  28. type
  29.    anystring = string[80];
  30.    FileStr = array[1..64] of char;
  31.  
  32.    ItemPointer = ^ItemList;
  33.    ItemList = record
  34.                  name : string[20];
  35.                  count : longint;
  36.                  next : ItemPointer;
  37.               end;
  38.  
  39.    FilePointer = ^FileRec;
  40.    FileRec = record
  41.                 name : string[16];
  42.                 count : longint;
  43.                 size : longint;
  44.                 higher : FilePointer;
  45.                 lower : FilePointer;
  46.              end;
  47.  
  48.    ProtocolRecord = record
  49.                        Code : char;
  50.                        Name : string[20];
  51.                        Uploads : longint; {count of uploads}
  52.                        UpTime : real; {time spent uploading}
  53.                        UpIdeal : real; {ideal time if 100% efficient}
  54.                        Downloads : longint;
  55.                        DownTime : real;
  56.                        DownIdeal : real;
  57.                     end;
  58.  
  59. const
  60.    ProtocolCount = 27;
  61.    Protocol : array[1..ProtocolCount] of ProtocolRecord = (
  62.       (Code : 'A'; Name : 'ASCII'),
  63.       (Code : 'B'; Name : 'B'),
  64.       (Code : 'C'; Name : 'CRC Xmodem'),
  65.       (Code : 'D'; Name : 'D'),
  66.       (Code : 'E'; Name : 'E'),
  67.       (Code : 'F'; Name : 'Full Flow'),
  68.       (Code : 'G'; Name : 'Ymodem-G (dsz)'),
  69.       (Code : 'H'; Name : 'H'),
  70.       (Code : 'I'; Name : 'I'),
  71.       (Code : 'J'; Name : 'Jmodem'),
  72.       (Code : 'K'; Name : 'Kermit'),
  73.       (Code : 'L'; Name : 'Sysop (Local)'),
  74.       (Code : 'M'; Name : 'MegaLink'),
  75.       (Code : 'N'; Name : 'N'),
  76.       (Code : 'O'; Name : '1K-Xmodem'),
  77.       (Code : 'P'; Name : 'PCP-Zmodem'),
  78.       (Code : 'Q'; Name : 'Q'),
  79.       (Code : 'R'; Name : 'Zmodem Resume'),
  80.       (Code : 'S'; Name : 'SEAlink'),
  81.       (Code : 'T'; Name : 'T'),
  82.       (Code : 'U'; Name : 'U'),
  83.       (Code : 'V'; Name : 'Overdrive SEAlink'),
  84.       (Code : 'W'; Name : 'Window Xmodem'),
  85.       (Code : 'X'; Name : 'Xmodem'),
  86.       (Code : 'Y'; Name : 'Ymodem Batch'),
  87.       (Code : 'Z'; Name : 'Zmodem Batch'),
  88.       (Code : '?'; Name : 'Others')  {must be last}
  89.    );
  90.  
  91.  
  92. (* -------------------------------------------------------- *)
  93. const
  94.    maxdir = 60;
  95.  
  96.    red:     string[7] = #27'[1;31m';
  97.    green:   string[7] = #27'[1;32m';
  98.    yellow:  string[7] = #27'[1;33m';
  99.    blue:    string[7] = #27'[1;34m';
  100.    magenta: string[7] = #27'[1;35m';
  101.    cyan:    string[7] = #27'[0;36m';
  102.    white:   string[7] = #27'[1;37m';
  103.    gray:    string[7] = #27'[0m';
  104.  
  105. var
  106.    search_dir: array[1..maxdir] of string[65];
  107.    search_dirs: integer;
  108.  
  109.  
  110. (* -------------------------------------------------------- *)
  111. var
  112.    first_record : word;
  113.    total_records : word;
  114.    viewmember : longint;   {number of arc member textviews}
  115.    extarc : longint;       {number of arc member extracts}
  116.    rearcs : longint;       {number of re-archive runs}
  117.    arctest : longint;      {number of archives tested}
  118.    arcview : longint;      {number of ARC views}
  119.    B1200 : longint;
  120.    B19200 : longint;       {Baud rate calls}
  121.    B2400 : longint;
  122.    B300 : longint;
  123.    B4800 : longint;
  124.    B9600 : longint;
  125.    backdos : longint;      {number of times back from dos}
  126.    batchs : longint;       {number of batch transfers}
  127.    baud : longint;         {current caller's baud rate}
  128.    Blocal : longint;
  129.    blts : longint;         {bulletins read}
  130.    caller : longint;       {number of callers}
  131.    comments : longint;     {number of comments}
  132.    dirscan : longint;      {number of DIR scans}
  133.    DOORs : longint;        {number of DOORs opened}
  134.    DosTimes : longint;     {how many times dropped to DOS}
  135.    down : longint;         {number of downloads}
  136.    d_abort : longint;      {number of download aborts}
  137.    elapsed_time : real;    {how long it takes the program to run}
  138.    Endtime : real;         {End time for program start}
  139.    events : longint;       {event timer activated}
  140.    even_parity : longint;  {7E callers}
  141.    free_down : longint;    {free downloads}
  142.    graphics : longint;     {graphics callers}
  143.    joins : longint;        {number of conference joins}
  144.    kills : longint;        {messages killed}
  145.    lockouts : longint;     {Automatic lockouts done}
  146.    logsize : word;
  147.    mssgs : longint;        {messages left}
  148.    new_guys : longint;     {new users registered}
  149.    non_graphics : longint; {non-graphics callers}
  150.    outfile : anystring;    {output filename}
  151.    PAGE : longint;         {sysop pages}
  152.    pwfail : longint;       {password fails}
  153.    question : longint;     {main questionnaire answered}
  154.    refused : longint;      {refused to register}
  155.    secviol : longint;      {security violations}
  156.    start_time : real;      {0 time for program start}
  157.    stuff : longint;
  158.    sysop_local : longint;  {local sysop sessions}
  159.    sysop_remote : longint; {remote sysop sessions}
  160.    tcan : longint;         {number of trashcan name attempts}
  161.    time_limit : longint;   {daily time limit exceeded}
  162.    TotHours : real;        {Total hours from first to last log entry}
  163.    UniqFiles : longint;    {number of dIfferent files}
  164.    up : longint;           {number of uploads}
  165.    u_abort : longint;      {number of upload aborts}
  166.    min_download : longint; {minimum nummber of downloads to include in report}
  167.    arcmail : longint;      {number of ARCM runs}
  168.    msgcount : longint;     {number of ARCM messges}
  169.    invalids : longint;     {number of invalid uploads}
  170.  
  171.    schat : longint;        {sysop chat initiated}
  172.    nchat:  longint;        {node chat initiated}
  173.       
  174.    UsedMinutes : longint;  {time used, minutes}
  175.    Hours : longint;        {time used, hours}
  176.    mins_dn : longint;      {minutes spent downloading}
  177.    mins_up : longint;      {minutes spent uploading}
  178.    mins_schat: longint;    {minutes spent in sysop-chat mode}
  179.    mins_nchat: longint;    {minutes spent in node-chat mode}
  180.    DosTime : longint;      {time spent in remote DOS}
  181.  
  182.    spare1 : longint;
  183.    spare2 : longint;
  184.    spare3 : longint;
  185.    spare4 : longint;
  186.    spare5 : longint;
  187.    spare6 : longint;
  188.    spare7 : longint;
  189.    spare8 : longint;
  190.    spare9 : longint;
  191.  
  192.  
  193.    Inrec : FileStr;        {64 char line}
  194.    PeriodCovered : anystring; {concats to send to ofd}
  195.    reports : anystring;    {list of reports to produce}
  196.    first_rec : string[64]; {first entry in log}
  197.  
  198.    {table of peak hours, 'Y'=peak, anything else=not}
  199.    PeakTable:  string[24];
  200.  
  201.    Hrs : array[0..23] of longint; {minutes used by hours}
  202.  
  203.    DiskFile : buffered_file;
  204.    FileTree : FilePointer;
  205.    FirstBatch : ItemPointer;
  206.    FirstBullet : ItemPointer;
  207.    FirstConf : ItemPointer;
  208.    FirstDoor : ItemPointer;
  209.    ofd : text;        {file that goes to the bulletin}
  210.    filever: integer;
  211.  
  212. const
  213.    graph_num = 100;
  214.    graph_set : string[3] = '░▓▒';
  215.  
  216. type
  217.    sort_keys = (percent_sort, name_sort, no_sort);
  218.  
  219. var
  220.    graph_min,
  221.    graph_max : longint;
  222.    graph_lim : real;
  223.    graph_line : longint;
  224.    graph_val : array[1..graph_num] of real;
  225.    graph_title : array[1..graph_num] of string[20];
  226.    graph_count : integer;
  227.  
  228.  
  229. (* -------------------------------------------------------- *)
  230. procedure section_title(title : anystring);
  231.    begin
  232.       writeln(ofd);
  233.       writeln(ofd, '' : 35-(length(title) div 2),
  234.             red, '-= ', yellow, title, red, ' =-');
  235.       writeln(ofd);
  236.    end;
  237.  
  238.  
  239. procedure empty_section;
  240.    begin
  241.       writeln(ofd, gray, '':34,'**NONE**');
  242.    end;
  243.  
  244.  
  245. procedure start_graph(title : anystring; limit : real);
  246.    begin
  247.       graph_lim := limit;
  248.       graph_max := 0;
  249.       graph_min := 100;
  250.       graph_line := 0;
  251.       graph_count := 0;
  252.       section_title(title);
  253.    end;
  254.  
  255. procedure graph(item : anystring; n : real);
  256.    var
  257.       pct : real;
  258.    begin
  259.       if graph_lim = 0 then
  260.          pct := 0
  261.       else
  262.          pct := abs(n/graph_lim)*100.0;
  263.       if (pct <= 0) or (pct > maxint) then
  264.          exit;
  265.  
  266.     { if pct > 100 then
  267.          pct := 100;   }
  268.  
  269.       if pct > graph_max then
  270.          graph_max := trunc(pct);
  271.       if pct < graph_min then
  272.          graph_min := trunc(pct*0.7);
  273.  
  274.       if graph_count < graph_num then
  275.          inc(graph_count);
  276.  
  277.       graph_val[graph_count] := n;
  278.       graph_title[graph_count] := item;
  279.    end;
  280.  
  281.  
  282. procedure graph_output(item : anystring; n : real);
  283.    var
  284.       pct : real;
  285.       i : integer;
  286.       w : integer;
  287.       lim : longint;
  288.    begin
  289.       if graph_line < length(graph_set) then
  290.          inc(graph_line)
  291.       else
  292.          graph_line := 1;
  293.  
  294.       if graph_lim = 0 then
  295.          pct := 0
  296.       else
  297.          pct := abs(n/graph_lim*100.0);
  298.  
  299.       if pct > 100 then
  300.          pct := 100;
  301.  
  302.       write(ofd, green, item:20, ': ', white);
  303.  
  304.       if graph_lim < 0 then
  305.          if pct >= 100 then
  306.             write(ofd,' 100% ')
  307.          else
  308.             write(ofd, pct:4:1, '% ')
  309.       else
  310.  
  311.       begin
  312.          if int(graph_lim) <> graph_lim then
  313.             write(ofd, n:5:1)
  314.          else
  315.             write(ofd, n:4:0);
  316.  
  317.          if pct >= 100 then
  318.             write(ofd,gray, ' ( 100%) ')
  319.          else
  320.             write(ofd,gray,' (', pct:4:1, '%) ');
  321.       end;
  322.  
  323.       if graph_lim < 0 then lim := 50 else lim := 42;
  324.  
  325.       if (pct < graph_min) then
  326.          w := 0
  327.       else
  328.       if (graph_min = graph_max) then
  329.          w := lim
  330.       else
  331.          w := round((pct-graph_min)/(graph_max-graph_min)*lim);
  332.  
  333.       if w > lim then
  334.          w := lim;
  335.  
  336.       write(ofd, white, '│', cyan);
  337.       for i := 1 to w-1 do
  338.          write(ofd, graph_set[graph_line]);
  339.       if w > 0 then
  340.          write(ofd, white, '█');
  341.  
  342.       writeln(ofd);
  343.    end;
  344.  
  345.  
  346.    procedure sort_graph(onkey: sort_keys);
  347.    var
  348.       ts : string[20];
  349.       tv : real;
  350.       swap : boolean;
  351.       i,j : integer;
  352.  
  353.       function swap_needed: boolean;
  354.       begin
  355.          if onkey = percent_sort then
  356.             tv := graph_val[i]-graph_val[i+1]
  357.          else
  358.             tv := 0;
  359.          if tv = 0 then
  360.             if graph_title[i] > graph_title[i+1] then
  361.                tv := -1;
  362.          swap_needed := (tv < 0);
  363.       end;
  364.       
  365.       procedure swap_entries;
  366.       begin
  367.          swap := true;
  368.          tv := graph_val[i+1];
  369.          graph_val[i+1] := graph_val[i];
  370.          graph_val[i] := tv;
  371.          ts := graph_title[i+1];
  372.          graph_title[i+1] := graph_title[i];
  373.          graph_title[i] := ts;
  374.       end;
  375.  
  376.    begin
  377.  
  378.      j := graph_count;
  379.      repeat
  380.          swap := false;
  381.          dec(j);
  382.          for i := 1 to j do
  383.             if swap_needed then
  384.                swap_entries;
  385.       until swap = false;
  386.    end;
  387.  
  388.  
  389. procedure end_graph(onkey: sort_keys);
  390.    var
  391.       i : integer;
  392.  
  393.    begin
  394.       if onkey <> no_sort then
  395.          sort_graph(onkey);
  396.  
  397.       for i := 1 to graph_count do
  398.          graph_output(graph_title[i], graph_val[i]);
  399.  
  400.       if graph_count = 0 then
  401.          empty_section;
  402.  
  403.       writeln(ofd);
  404.    end;
  405.  
  406.  
  407. (* -------------------------------------------------------- *)
  408.    procedure graph_list(node: ItemPointer;
  409.                         title: string; 
  410.                         n: real; key: sort_keys);
  411.    begin
  412.       start_graph(title,n);
  413.       while node <> nil do
  414.          begin
  415.             graph(node^.name, node^.count);
  416.             node := node^.next;
  417.          end;
  418.       end_graph(key);
  419.    end;
  420.  
  421.  
  422. (* -------------------------------------------------------- *)
  423. procedure walk_tree( var Node : FilePointer;
  424.                      var a : integer);
  425.    {traverse the binary filename tree and output in sorted order}
  426. begin
  427.    if Node = nil then exit;
  428.  
  429.    walk_tree(Node^.lower, a);
  430.  
  431.    if Node^.count >= min_download then
  432.    begin
  433.       case Node^.count-min_download of
  434.          0.. 2: write(ofd, cyan,   '     ');
  435.          3.. 6: write(ofd, green,  '   * ');
  436.          7..12: write(ofd, red,    '  ** ');
  437.         13..24: write(ofd, yellow, ' *** ');
  438.          else   write(ofd, white,  '**** ');
  439.       end;
  440.  
  441.       write(ofd, Node^.name : 12, Node^.count : 5);
  442.  
  443.       if a mod 3 = 0 then
  444.          writeln(ofd)
  445.       else
  446.          write(ofd,'   ');
  447.  
  448.       inc(a);
  449.    end;
  450.  
  451.    walk_tree(Node^.higher, a);
  452. end;
  453.  
  454.  
  455. (* -------------------------------------------------------- *)
  456. procedure output_results(outfile: anystring);
  457.    var
  458.       UsedHours : real;
  459.       H24 : real;
  460.       DownEffic : real;
  461.       UpEffic : real;
  462.       temp : anystring;
  463.       Days : longint;
  464.       report : integer;
  465.       c: char;
  466.       PeakUsed : real;
  467.       PeakHours : real;
  468.  
  469.       procedure init_report;
  470.       var
  471.          i,j: integer;
  472.       begin
  473.          gotoxy(15, 15);
  474.          HIGHVIDEO;
  475.          textcolor(14);
  476.          gotoxy(1, 2);
  477.          write('Sending output to ', outfile,' ');
  478.          gotoxy(1, 24);
  479.  
  480.          assign(ofd, outfile);
  481.          rewrite(ofd);
  482.  
  483.          UsedHours := int(UsedMinutes)/60.0+int(Hours);
  484.  
  485.          if TotHours < 1 then
  486.             TotHours := 1;
  487.          Days := trunc((TotHours+23.0)/24.0);
  488.          str(days,temp);
  489.  
  490.          {calculate number of hours in peak times}
  491.          i := 0;
  492.          for j := 0 to 23 do
  493.             if PeakTable[j+1] = 'Y' then
  494.                inc(i);
  495.          if i = 0 then
  496.             i := 24;
  497.          PeakHours := TotHours / 24.0 * int(i);
  498.  
  499.          {calculate time used in peak times}
  500.          if i = 24 then
  501.             PeakUsed := UsedHours
  502.          else
  503.          begin
  504.             PeakUsed := 0;
  505.             for j := 0 to 23 do
  506.                if PeakTable[j+1] = 'Y' then
  507.                   PeakUsed := PeakUsed + int(hrs[j])/60.0;
  508.          end;
  509.  
  510.          writeln(ofd,white);
  511.          writeln(ofd, '                  Calls ', version, ' - Call Analyzer ',pcbversion);
  512.          writeln(ofd, blue, '            ', PeriodCovered);
  513.       end;
  514.  
  515.       procedure system_statistics;
  516.       begin
  517.          section_title('System Statistics for '+temp+' days');
  518.  
  519.          write  (ofd, green, '  Archive REPAK Runs .... ', white, rearcs:6);
  520.          writeln(ofd, green, '  Comments Left ......... ':33, white, comments:6);
  521.  
  522.          write  (ofd, green, '  Archive Texts Viewed .. ', white, viewmember:6);
  523.          writeln(ofd, green, '  Messages Left ......... ':33, white, mssgs:6);
  524.  
  525.          write  (ofd, green, '  Archive Extracts ...... ', white, extarc:6);
  526.          writeln(ofd, green, '  Archive Mail Runs ..... ':33, white, arcmail:6);
  527.  
  528.          write  (ofd, green, '  Archives Tested ....... ', white, arctest:6);
  529.          writeln(ofd, green, '  Archive Mail Messages . ':33, white, msgcount:6);
  530.  
  531.          write  (ofd, green, '  Archives Viewed ....... ', white, arcview:6);
  532.          writeln(ofd, green, '  Number of Callers ..... ':33, white, caller:6);
  533.  
  534.          write  (ofd, green, '  Directory Scans ....... ', white, dirscan:6);
  535.          writeln(ofd, green, '  New Users Registered .. ':33, white, new_guys:6);
  536.  
  537.          write  (ofd, green, '  Doors Opened .......... ', white, DOORs:6);
  538.          writeln(ofd, green, '  Questionnaire Answered. ':33, white, question:6);
  539.  
  540.          write  (ofd, green, '  Downloads Aborted ..... ', white, d_abort:6);
  541.          writeln(ofd, green, '  Average Call Length ... ':33, white, (UsedHours*60)/caller:6:1);
  542.  
  543.          write  (ofd, green, '  Downloads Completed ... ', white, down:6);
  544.          writeln(ofd, green, '  Average Idle Time ..... ':33, white, (TotHours-UsedHours)*60/caller:6:1);
  545.  
  546.          write  (ofd, green, '  Different Files Dnld .. ', white, UniqFiles:6);
  547.          writeln(ofd, green, '  Calls per day (avg) ... ':33, white, caller/Days:6:1);
  548.  
  549.          write  (ofd, green, '  Free downloads ........ ', white, free_down:6);
  550.          writeln(ofd, green, '  Time Used, Hours ...... ':33, white, UsedHours:6:1);
  551.  
  552.          write  (ofd, green, '  Uploads Aborted ....... ', white, u_abort:6);
  553.          writeln(ofd, green, '  Total Operation Hours . ':33, white, TotHours:6:1);
  554.  
  555.          write  (ofd, green, '  Uploads Completed ..... ', white, up:6);
  556.          writeln(ofd, green, '  Total Utilization % ... ':33, white, (UsedHours/TotHours)*100:6:1);
  557.  
  558.          write  (ofd, green, '  Bad archives deleted .. ', white, invalids:6);
  559.          writeln(ofd, green, '  Peak Utilization % .... ':33, white, (PeakUsed/PeakHours)*100:6:1);
  560.          writeln(ofd);
  561.       end;
  562.  
  563.       procedure security_statistics;
  564.       begin
  565.          section_title('Security Statistics');
  566.  
  567.          write  (ofd, '':32);
  568.          writeln(ofd, green, '  Node Chats Initiated... ':33, white, nchat:6);
  569.  
  570.          write  (ofd, green, '  Automatic Lockouts .... ', white, lockouts:6);
  571.          writeln(ofd, green, '  Sysop Chats Initiated.. ':33, white, schat:6);
  572.  
  573.          write  (ofd, green, '  Password Failures ..... ', white, pwfail:6);
  574.          writeln(ofd, green, '  Sysop Paged ........... ':33, white, PAGE:6);
  575.  
  576.          write  (ofd, green, '  Refused to Register ... ', white, refused:6);
  577.          writeln(ofd, green, '  Sysop Sessions ........ ':33, white, sysop_local+sysop_remote:6);
  578.  
  579.          write  (ofd, green, '  Remote DOS Time (min) . ', white, DosTime:6);
  580.          writeln(ofd, green, '  Time Limit Expired .... ':33, white, time_limit:6);
  581.  
  582.          write  (ofd, green, '  Remote Drops to DOS ... ', white, DosTimes:6);
  583.          writeln(ofd, green, '  Trashcan Names ........ ':33, white, tcan:6);
  584.  
  585.          write  (ofd, green, '  Scheduled Events ...... ', white, events:6);
  586.          writeln(ofd, green, '  Security Violations ... ':33, white, secviol:6);
  587.          writeln(ofd);
  588.       end;
  589.  
  590.       procedure graphic_modes;
  591.       var
  592.          k: longint;
  593.       begin
  594.          k := (graphics+non_graphics+even_parity);
  595.          start_graph('Graphics Modes', k);
  596.          graph('Color Graphics', graphics);
  597.          graph('Non Graphics', non_graphics);
  598.          graph('7 Bit Even-Parity', even_parity);
  599.          end_graph(percent_sort);
  600.       end;
  601.  
  602.       procedure baud_rates;
  603.       begin
  604.          start_graph('Baud Rates', B19200+B9600+B4800+B2400+B1200+B300);
  605.          graph('19200 Baud', B19200);
  606.          graph('9600 Baud', B9600);
  607.          graph('4800 Baud', B4800);
  608.          graph('2400 Baud', B2400);
  609.          graph('1200 Baud', B1200);
  610.          graph('300 Baud', B300);
  611.          end_graph(no_sort);
  612.       end;
  613.  
  614.       procedure hourly_usage;
  615.       var
  616.          hits: longint;
  617.          slot: integer;
  618.          a:    integer;
  619.          k:    integer;
  620.       begin
  621.          section_title('Average Percent of Hourly Usage');
  622.          if TotHours > 24 then H24 := (TotHours/24)*(60/100)
  623.          else H24 := 0.60;
  624.  
  625.          hits := 0;
  626.          for k := 20 downto 1 do 
  627.          {if hits < 24 then}
  628.          begin
  629.             write(ofd, green, k*5 : 3, '%', white, ' │ ');
  630.             hits := 0;
  631.  
  632.             for a := 0 to 23 do 
  633.             begin
  634.                c := graph_set[(a mod 3)+1];
  635.                slot := trunc((hrs[a] / H24) / 5);
  636.                if slot > 20 then slot := 20;
  637.                if slot = k then
  638.                   write(ofd, white, '██ ')
  639.                else
  640.                if slot > k then
  641.                begin
  642.                   write(ofd, cyan, c,c,' ');
  643.                   inc(hits);
  644.                end
  645.                else 
  646.                   write(ofd, blue, ' · ');
  647.             end;
  648.  
  649.             writeln(ofd);
  650.          end;
  651.  
  652.          write(ofd, green, '       00');
  653.          for a := 1 to 23 do
  654.             write(ofd,a:3);
  655.          writeln(ofd);
  656.  
  657.          write(ofd, yellow, 'Peak: ', magenta);
  658.          for a := 0 to 23 do
  659.             if PeakTable[a+1] = 'Y' then
  660.                write(ofd,' **')
  661.             else
  662.                write(ofd,'   ');
  663.          writeln(ofd);
  664.          writeln(ofd);
  665.       end;
  666.  
  667.       procedure conferences_joined;
  668.       begin
  669.          graph_list(FirstConf,'Conferences Joined', joins, percent_sort);
  670.       end;
  671.  
  672.       procedure bulletins_read;
  673.       begin
  674.          graph_list(FirstBullet,'Bulletins Read', blts, percent_sort);
  675.       end;
  676.  
  677.       procedure doors_opened;
  678.       begin
  679.          graph_list(FirstDoor,'Doors Opened', DOORs, percent_sort);
  680.       end;
  681.  
  682.       procedure time_distribution;
  683.       begin
  684.       end;
  685.  
  686.       procedure download_protocols;
  687.       var
  688.          k: integer;
  689.       begin
  690.          start_graph('Protocol Usage (Downloading)', down);
  691.          for k := 1 to ProtocolCount do
  692.             with Protocol[k] do
  693.                if (Downloads <> 0) then
  694.                   graph(Name, Downloads);
  695.          end_graph(percent_sort);
  696.       end;
  697.  
  698.       procedure download_efficiency;
  699.       var
  700.          k: integer;
  701.       begin
  702.          start_graph('Average Protocol Efficiency (Downloading)', -100);
  703.          for k := 1 to ProtocolCount do
  704.             with Protocol[k] do
  705.                if (Downloads <> 0) and (DownTime <> 0) then
  706.                   begin
  707.                      DownEffic := 100.0*DownIdeal/DownTime;
  708.                      graph(Name, DownEffic);
  709.                   end;
  710.          end_graph(percent_sort);
  711.       end;
  712.  
  713.       procedure upload_protocols;
  714.       var
  715.          k: integer;
  716.       begin
  717.          start_graph('Protocol Usage (Uploading)', up);
  718.          for k := 1 to ProtocolCount do
  719.             with Protocol[k] do
  720.                if (Uploads <> 0) then
  721.                   graph(Name, Uploads);
  722.          end_graph(percent_sort);
  723.       end;
  724.  
  725.       procedure upload_efficiency;
  726.       var
  727.          k: integer;
  728.       begin
  729.          start_graph('Average Protocol Efficiency (Uploading)', -100);
  730.          for k := 1 to ProtocolCount do
  731.             with Protocol[k] do
  732.                if (Uploads <> 0) and (UpTime <> 0) then
  733.                   begin
  734.                      UpEffic := 100.0*UpIdeal/UpTime;
  735.                      graph(Name, UpEffic);
  736.                   end;
  737.          end_graph(percent_sort);
  738.       end;
  739.  
  740.       procedure batch_sizes;
  741.       begin
  742.          graph_list(FirstBatch,'Batch Transfer Sizes', batchs, name_sort);
  743.       end;
  744.  
  745.       procedure files_downloaded;
  746.       var
  747.          a: integer;
  748.       begin
  749.          section_title('Files Downloaded');
  750.          if down < 1 then
  751.             empty_section
  752.          else
  753.             begin
  754.                a := 1;
  755.                walk_tree(FileTree, a);
  756.             end;
  757.          writeln(ofd);
  758.       end;
  759.  
  760. (* -------------------------------------------------------- *)
  761.    begin
  762.       init_report;
  763.  
  764.       for report := 1 to length(reports) do
  765.          case upcase(reports[report]) of
  766.            'A': system_statistics;
  767.            'B': graphic_modes;
  768.            'C': baud_rates;
  769.            'D': hourly_usage;
  770.            'E': conferences_joined;
  771.            'F': bulletins_read;
  772.            'G': doors_opened;
  773.            'H': download_protocols;
  774.            'I': download_efficiency;
  775.            'J': upload_protocols;
  776.            'K': upload_efficiency;
  777.            'L': batch_sizes;
  778.            'M': files_downloaded;
  779.            'N': security_statistics;
  780.            'O': time_distribution;
  781.            'Z': writeln(ofd);
  782.          end;
  783.  
  784.       write(ofd,gray);
  785.       close(ofd);
  786.    end;
  787.  
  788.  
  789.  
  790. (* -------------------------------------------------------- *)
  791. procedure getrec;
  792.    var
  793.       c:    char;
  794.    begin
  795.       bread(DiskFile, Inrec);
  796.  
  797.       if keypressed then
  798.       begin
  799.          c := readkey;
  800.          if c = #27 then
  801.          begin
  802.             gotoxy(1, 24);
  803.             writeln('** ESC pressed - Aborted **');
  804.             delay(2000);
  805.             halt;
  806.          end;
  807.       end;
  808.  
  809.    end;
  810.  
  811.  
  812. (* -------------------------------------------------------- *)
  813. function get_file_size(name: string): longint;
  814.    {get the size of a file; somewhere in download paths}
  815. var
  816.    path:    string;
  817.    i:       integer;
  818.    DirInfo: SearchRec;
  819.  
  820. begin
  821. (***
  822.    name[9] := '.';
  823.    repeat
  824.       i := pos(' ',name);
  825.       if i >0 then
  826.          delete(name,i,1);
  827.    until i = 0;
  828.  
  829.    for i := 1 to search_dirs do
  830.    begin
  831.       path := search_dir[i] + '\' + name;
  832.  
  833.       FindFirst(path,$21,DirInfo);
  834.       if (DosError = 0) then
  835.       begin
  836.          gotoxy(23,3);
  837.          write('File: ',name:12,'   Size:',dirinfo.size:7);
  838.          get_file_size := DirInfo.size;
  839.          exit;
  840.       end;
  841.    end;
  842.  
  843.    gotoxy(23,3);
  844.    write('File: ',name:12,'  Not found!  ');
  845. ***)
  846.    get_file_size := 60000;
  847. end;
  848.  
  849.  
  850. (* -------------------------------------------------------- *)
  851. procedure add_item(var FirstItem : ItemPointer;
  852.                    ItemName : anystring;
  853.                    Number : integer);
  854. var
  855.    NewItem : ItemPointer;
  856.  
  857. begin
  858.    NewItem := FirstItem;
  859.    while NewItem <> nil do
  860.       if NewItem^.name = ItemName then
  861.          begin
  862.             NewItem^.count := NewItem^.count + Number;
  863.             exit;
  864.          end
  865.       else
  866.          NewItem := NewItem^.next;
  867.  
  868.    new(NewItem);          { get a new record}
  869.    NewItem^.next := FirstItem;
  870.    FirstItem := NewItem;
  871.    NewItem^.name := ItemName;
  872.    NewItem^.count := Number;
  873. end;
  874.  
  875.  
  876. (* -------------------------------------------------------- *)
  877. procedure store_name(var Node : FilePointer;
  878.                      var Name : anystring;
  879.                      var Size : longint);
  880.       {stores the name in the sorted name tree; recursive}
  881.  
  882.    begin
  883.  
  884.       (* insert new nodes *)
  885.       if Node = nil then
  886.       begin
  887.          new(Node);
  888.          Node^.count := 1;
  889.          Node^.name := Name;
  890.          Node^.size := get_file_size(Name);
  891.          Size := Node^.size;
  892.          Node^.higher := nil;
  893.          Node^.lower := nil;
  894.          inc(UniqFiles);
  895.       end
  896.       else
  897.  
  898.       (* count existting nodes *)
  899.       if Node^.name = Name then
  900.       begin
  901.          inc(Node^.count);
  902.          Size := Node^.size;
  903.       end
  904.       else
  905.  
  906.       (* else traverse the tree looking for the right node *)
  907.       if Name > Node^.name then
  908.          store_name(Node^.higher,Name,Size)
  909.       else
  910.          store_name(Node^.lower,Name,Size);
  911.    end;
  912.  
  913.  
  914. (* -------------------------------------------------------- *)
  915. type
  916.    str12 = string[12];
  917.    str80 = string[80];
  918.  
  919. {  This Function returns a name expanded to line up both the name and ext    }
  920. {  for example:  abc.com      =  abc      com                                }
  921. {                datafile.1   =  datafile   1                                }
  922.  
  923. function ExpandName(name : str12) : str12;
  924.  
  925.    var
  926.       Counter, DotPos : integer;
  927.  
  928.    begin
  929.       DotPos := pos('.', name); {where's the dot at?}
  930.       if DotPos = 0 then begin
  931.          repeat
  932.             name := name+' '; {If no ext, pad with spaces}
  933.          until length(name) = 12;
  934.       end else begin
  935.          delete(name, DotPos, 1);
  936.          repeat
  937.             insert(' ', name, DotPos);
  938.          until length(name) = 12;
  939.       end;
  940.       ExpandName := name;
  941.    end;
  942.  
  943.  
  944. (* -------------------------------------------------------- *)
  945. procedure print(col, row : integer;
  946.                 str : str80;
  947.                 Attrib : integer);
  948.    begin
  949.       gotoxy(col, row);
  950.       textcolor(Attrib);
  951.       write(str);
  952.    end;
  953.  
  954.  
  955. (* -------------------------------------------------------- *)
  956. function Time : real;
  957.  
  958.    var
  959.       Reg : Registers;
  960.  
  961.    begin Reg.AX := $2C00;
  962.       intr($21, Reg);
  963.       Time := (Reg.CX shr 8)*3600 {Hours}
  964.       +(Reg.CX and $00FF)*60 {Minutes}
  965.       +(Reg.DX shr 8)      { * 1 }
  966.                            {Seconds    }
  967.       +(Reg.DX and $00FF)/100; {Hundredths }
  968.    end;
  969.  
  970.  
  971.  
  972. (* -------------------------------------------------------- *)
  973. procedure incaller;
  974.    var
  975.       Str30 : string[30];
  976.       posit : integer;
  977.       str20 : string[20];
  978.  
  979.    begin
  980.       if pos('New', Inrec) > 0 then
  981.          exit;
  982.       if pos('Off', Inrec) > 0 then
  983.          exit;
  984.  
  985.       if pos(' SYSOP (', Inrec) > 0 then
  986.          begin
  987.             if pos(' (Local) (', Inrec) > 0 then inc(sysop_local)
  988.             else inc(sysop_remote);
  989.          end;
  990.  
  991.       if pos(' (Local) (', Inrec) <> 0 then baud := 0
  992.       else if pos(' (19200) (', Inrec) <> 0 then baud := 19200
  993.       else if pos(' (9600) (', Inrec) <> 0 then baud := 9600
  994.       else if pos(' (4800) (', Inrec) <> 0 then baud := 4800
  995.       else if pos(' (2400) (', Inrec) <> 0 then baud := 2400
  996.       else if pos(' (1200) (', Inrec) <> 0 then baud := 1200
  997.       else if pos(' (300) (', Inrec) <> 0 then baud := 300;
  998.  
  999.       case baud of
  1000.          19200 : begin
  1001.                     inc(B19200);
  1002.                     baud := 13000;  {highest effective speed}
  1003.                  end;
  1004.  
  1005.          9600 :  inc(B9600);
  1006.          4800 :  inc(B4800);
  1007.          2400 :  inc(B2400);
  1008.          1200 :  inc(B1200);
  1009.          300 :   inc(B300);
  1010.       else inc(Blocal);
  1011.       end;
  1012.  
  1013.       if pos('(G', Inrec) > 0 then inc(graphics)
  1014.       else if pos('(N', Inrec) > 0 then inc(non_graphics)
  1015.       else if pos('(7', Inrec) > 0 then inc(even_parity);
  1016.  
  1017.       caller := Blocal+B300+B1200+B2400+B4800+B9600+B19200;
  1018.  
  1019.       if pos('Trashcan', Inrec) > 0 then inc(tcan);
  1020.    end;
  1021.  
  1022.  
  1023. (* -------------------------------------------------------- *)
  1024. procedure indownload;      {upload/downloaded file stuff}
  1025.    var
  1026.       prot : char;
  1027.       posit : integer;
  1028.       k : integer;
  1029.       CPS : real;
  1030.       FileName : string[12];
  1031.       tmp: string;
  1032.       size : longint;
  1033.       ideal : real;
  1034.       Time : real;
  1035.  
  1036.    begin
  1037.       if pos(' Aborted using ', Inrec) > 12 then
  1038.       begin
  1039.          if inrec[8] = 'D' then
  1040.             inc(d_abort) {Aborted dl's}
  1041.          else
  1042.             inc(u_abort);
  1043.          exit;
  1044.       end;
  1045.  
  1046.       if inrec[8] = 'D' then
  1047.          inc(down)
  1048.       else
  1049.          inc(up);
  1050.  
  1051.       {determine file name}
  1052.       posit := pos(' Completed using ', Inrec); {find End of name}
  1053.       if posit=0 then exit;
  1054.  
  1055.       FileName := copy(Inrec, 11, (posit-11));
  1056.       FileName := ExpandName(FileName);
  1057.       if FileName[1] = ' ' then exit;
  1058.  
  1059.       {store name, return file size}
  1060.       store_name(FileTree,FileName,size);
  1061.  
  1062.       {determine transfer time}
  1063.       if baud <> 0 then
  1064.          ideal := size/baud*10.0
  1065.       else
  1066.          ideal := 111;
  1067.  
  1068.       {determine actual transfer time}
  1069.       posit := pos('CPS=', Inrec);
  1070.       if posit = 0 then
  1071.          CPS := baud/11.0
  1072.       else
  1073.       begin
  1074.          tmp := copy(inrec,posit+4,6);
  1075.          posit := pos(' ',tmp);
  1076.          tmp := copy(tmp,1,posit-1);
  1077.          CPS := 0;
  1078.          val(tmp,cps,posit);
  1079.       end;
  1080.  
  1081.       if (CPS < 20) or (CPS > (baud/5.0)) then
  1082.       begin
  1083.          Time := 0;     {don't consider aborted or invalid transfers}
  1084.          ideal := 0;
  1085.       end
  1086.       else
  1087.          Time := size/CPS;
  1088.  
  1089.       if inrec[8] = 'D' then
  1090.       begin
  1091.          inc(down);
  1092.          mins_dn := mins_dn + round(Time/60.0);
  1093.       end
  1094.       else
  1095.       begin
  1096.          inc(up);
  1097.          mins_up := mins_up + round(Time/60.0);
  1098.       end;
  1099.  
  1100.       {determine protocol and find table entry}
  1101.       posit := pos('using ', Inrec);
  1102.       prot := Inrec[posit+6];
  1103.  
  1104.       for k := 1 to ProtocolCount do
  1105.       with Protocol[k] do
  1106.  
  1107.          if (Code = prot) or (Code = '?') then
  1108.          begin
  1109.             if Code = '?' then
  1110.             begin
  1111.                gotoxy(1,3);
  1112.                writeln('Unknown protocol: ',Inrec);
  1113.             end;
  1114.  
  1115.             if Inrec[8] = 'D' then
  1116.             begin
  1117.                inc(Downloads);
  1118.                DownTime := DownTime+Time;
  1119.                DownIdeal := DownIdeal+ideal;
  1120.             end
  1121.             else
  1122.             begin
  1123.                inc(Uploads);
  1124.                UpTime := UpTime+Time;
  1125.                UpIdeal := UpIdeal+ideal;
  1126.             end;
  1127.  
  1128.             exit;
  1129.          end;
  1130.    end;
  1131.  
  1132.  
  1133. (* -------------------------------------------------------- *)
  1134. procedure confjoin;        {conferences joined}
  1135.  
  1136.    var
  1137.       posit : integer;
  1138.       ConfName : anystring;
  1139.  
  1140.    begin
  1141.       posit := pos(' Conference', Inrec);
  1142.       if posit < 8 then
  1143.          exit;
  1144.  
  1145.       ConfName := copy(Inrec, 7, 10);
  1146.       posit := pos(' ',ConfName);
  1147.       if posit > 0 then
  1148.          ConfName[0] := chr(posit-1);
  1149.  
  1150.       case ConfName[1] of
  1151.          '0'..'9', 'a'..'z', 'A'..'Z':
  1152.          begin
  1153.             inc(joins);
  1154.             add_item(FirstConf, ConfName, 1);
  1155.          end;
  1156.       end;
  1157.    end;
  1158.  
  1159.  
  1160. (* -------------------------------------------------------- *)
  1161. procedure batch;        {batch transfer}
  1162.  
  1163.    var
  1164.       posit : integer;
  1165.       num : integer;
  1166.       temp : anystring;
  1167.       BatchName : anystring;
  1168.  
  1169.    begin
  1170.       posit := pos(' files', Inrec);
  1171.       temp := copy(Inrec,7,posit-7);
  1172.       num := 0;
  1173.       val(temp,num,posit);
  1174.       if num < 1 then
  1175.          exit;
  1176.       if Inrec[posit+7] = '0' then
  1177.          exit;
  1178.  
  1179.       str(num:2,temp);
  1180.       if num = 1 then
  1181.          BatchName := '  Single Files'
  1182.       else
  1183.          BatchName := temp + ' Files';
  1184.  
  1185.       batchs := batchs + num;
  1186.       add_item(FirstBatch, BatchName, num);
  1187.    end;
  1188.  
  1189.  
  1190. (* -------------------------------------------------------- *)
  1191. procedure arcmsgs;        {archived message count}
  1192.    var
  1193.       posit : integer;
  1194.       num : integer;
  1195.    
  1196.    begin
  1197.       posit := pos(' messa', Inrec);
  1198.       num := 0;
  1199.       val(copy(Inrec,7,posit-7),num,posit);
  1200.       if num < 1 then
  1201.          exit;
  1202.       msgcount := msgcount + num;
  1203.    end;
  1204.  
  1205.  
  1206. (* -------------------------------------------------------- *)
  1207. type
  1208.    Days = integer;
  1209. var
  1210.    numdays : integer;
  1211.  
  1212. function finday(Days : integer) : integer;
  1213.  
  1214.    begin
  1215.       case Days of
  1216.          12 : numdays := 334;
  1217.          11 : numdays := 304;
  1218.          10 : numdays := 273;
  1219.          9 : numdays := 243;
  1220.          8 : numdays := 212;
  1221.          7 : numdays := 181;
  1222.          6 : numdays := 151;
  1223.          5 : numdays := 120;
  1224.          4 : numdays := 90;
  1225.          3 : numdays := 59;
  1226.          2 : numdays := 31;
  1227.          1 : numdays := 0;
  1228.       end;                 {case}
  1229.       finday := numdays;
  1230.    end;
  1231.  
  1232.  
  1233. (* -------------------------------------------------------- *)
  1234. procedure openfiles;
  1235.  
  1236.    var
  1237.       end_hours: real;
  1238.       beg_hours: real;
  1239.       mostr, daystr : integer;
  1240.       YrStr, Fract : real;
  1241.       Num_Days : integer;
  1242.       TX : string[62];
  1243.       first_entry : string[19]; {first entry in log}
  1244.       last_entry : string[19]; {last entry in log}
  1245.       a: integer;
  1246.       inName : string[65];
  1247.  
  1248.    begin
  1249.       if paramcount = 0 then 
  1250.          InName :=  'CALLERS'
  1251.       else 
  1252.          InName := paramstr(1);
  1253.  
  1254.       bopen(DiskFile,InName,200,sizeof(InRec));
  1255.       if berr then
  1256.       begin
  1257.          writeln('Cant open caller file: ',InName);
  1258.          halt(1);
  1259.       end;
  1260.  
  1261.       bseekeof(DiskFile);
  1262.       total_records := btell(DiskFile);
  1263.       if total_records < 4 then
  1264.       begin
  1265.          gotoxy(1,24);
  1266.          writeln('Empty caller log - No action taken');
  1267.          halt(99);
  1268.       end;
  1269.  
  1270.       bseek(DiskFile, total_records-1);
  1271.       getrec;
  1272.  
  1273.       if inrec[3] <> '-' then             {check for bad EOF}
  1274.       begin
  1275.          repeat
  1276.             dec(total_records);
  1277.             bseek(DiskFile, total_records-1);
  1278.             getrec;
  1279.          until (inrec[3] = '-') or (total_records < 2);
  1280.       end;
  1281.  
  1282.       {decode the last log entry}
  1283.       dec(total_records);
  1284.       bseek(DiskFile, total_records);
  1285.       getrec;
  1286.  
  1287.       last_entry := copy(Inrec, 11, 5)+' '+copy(Inrec, 1, 8);
  1288.       TX := concat('Last log entry:  '+Inrec);
  1289.       print(3, 23, TX, 10);
  1290.  
  1291.       val(copy(last_entry, 7, 2), mostr, a);     {get month}
  1292.       val(copy(last_entry, 10, 2), daystr, a);   {get day}
  1293.       val(last_entry[14], YrStr, a);             {last digit of year}
  1294.       val(copy(last_entry, 1, 2), end_hours, a); {hour digit of logon}
  1295.       if end_hours > 23 then
  1296.          end_hours := end_hours - 24;
  1297.       val(copy(last_entry, 4, 2), Fract, a);
  1298.       Fract := Fract/60;
  1299.       Num_Days := finday(mostr);
  1300.       end_hours := end_hours + (YrStr*24*365) + Fract + (Num_Days+daystr)*24;
  1301.  
  1302.  
  1303.       {decode the beginning of the logfile}
  1304.       first_record := 0;
  1305.       repeat
  1306.          inc(first_record);
  1307.          bseek(DiskFile, first_record);
  1308.          getrec;
  1309.       until (Inrec[3] = '-') or (first_record >= total_records);
  1310.  
  1311.       if first_rec = '' then
  1312.          first_rec := Inrec;
  1313.       first_entry := copy(first_rec, 11, 5)+' '+copy(first_rec, 1, 8);
  1314.       TX := 'First log entry: '+first_rec;
  1315.       print(3, 22, TX, 10);
  1316.  
  1317.       val(copy(first_entry, 7, 2), mostr, a);
  1318.       val(copy(first_entry, 10, 2), daystr, a);
  1319.       val(first_entry[14], YrStr, a);
  1320.       val(copy(first_entry, 1, 2), beg_hours, a);
  1321.       if beg_hours > 23 then
  1322.          beg_hours := beg_hours - 24;
  1323.       val(copy(first_entry, 4, 2), Fract, a);
  1324.       Fract := Fract/60;
  1325.       Num_Days := finday(mostr);
  1326.       beg_hours := beg_hours + (YrStr*24*365) + Fract + (Num_Days+daystr)*24;
  1327.  
  1328.  
  1329.       {determine the period involved}
  1330.       PeriodCovered := 'Period covered:  From '+first_entry+' to '+last_entry;
  1331.       print(3, 21, PeriodCovered, 13);
  1332.  
  1333.       TotHours := end_hours-beg_hours;
  1334.       str(TotHours : 5 : 1, TX);
  1335.       TX := concat('Total Hours of Operation: ', TX);
  1336.       print(3, 19, TX, 15);
  1337.  
  1338.  
  1339.       logsize := total_records;
  1340.       str(logsize : 5, TX);
  1341.       TX := concat('Total Records in the Callers file: ', TX);
  1342.       print(3, 20, TX, crt.yellow);
  1343.  
  1344.       if total_records < 4 then
  1345.       begin
  1346.          gotoxy(1,24);
  1347.          writeln('Empty caller log - No action taken');
  1348.          halt(99);
  1349.       end;
  1350.  
  1351.       dec(total_records,2);
  1352.       incaller;
  1353.    end;
  1354.  
  1355.  
  1356.  
  1357. (* -------------------------------------------------------- *)
  1358. procedure bulletins;
  1359.  
  1360.    var
  1361.       posit : integer;
  1362.       BltNumber:  anystring;
  1363.       BltName:    anystring;
  1364.  
  1365.    begin
  1366.       BltName := copy(Inrec, 22, 10);
  1367.       posit := pos(' ', BltName);
  1368.       if posit > 0 then
  1369.          BltName[0] := chr(posit-1);
  1370.       if length(BltName) = 0 then
  1371.          exit;
  1372.  
  1373.       posit := pos('#', Inrec);
  1374.       if posit = 0 then
  1375.          exit;
  1376.       BltNumber := copy(Inrec,posit+2,4);
  1377.       posit := pos(' ', BltNumber);
  1378.       if posit > 0 then
  1379.          BltNumber[0] := chr(posit-1);
  1380.       while length(BltNumber) < 3 do
  1381.          BltNumber := ' ' + BltNumber;
  1382.  
  1383.       BltName := BltName + ' #' + BltNumber;
  1384.       inc(blts);
  1385.       add_item(FirstBullet, BltName, 1);
  1386.    end;                    {bulletins}
  1387.  
  1388.  
  1389. (* -------------------------------------------------------- *)
  1390. procedure pdoors;
  1391.  
  1392.    var
  1393.       posit : integer;
  1394.       DoorName : string[40];
  1395.  
  1396.    begin
  1397.       if pos(' at ', Inrec) = 0 then exit;
  1398.  
  1399.       posit := pos('(', Inrec);
  1400.       DoorName := copy(Inrec, posit+1, pos(')', Inrec)-posit-1);
  1401.  
  1402.       posit := 1;
  1403.       repeat
  1404.          if DoorName[posit] = '\' then
  1405.             begin
  1406.                DoorName := copy(DoorName, posit+1, 99);
  1407.                posit := 1;
  1408.             end
  1409.          else
  1410.             posit := posit+1;
  1411.       until posit = length(DoorName);
  1412.  
  1413.       inc(DOORs);
  1414.       add_item(FirstDoor, DoorName, 1);
  1415.    end;
  1416.  
  1417.  
  1418. (* -------------------------------------------------------- *)
  1419. procedure DOSdrop;
  1420.  
  1421.    var
  1422.       DT1, DT2 : integer;
  1423.       a: integer;
  1424.  
  1425.    begin
  1426.       val(copy(Inrec, 34, 2), DT1, a); {exit to DOS time}
  1427.       getrec;
  1428.  
  1429.       val(copy(Inrec, 27, 2), DT2, a); {back from DOS time}
  1430.       if a = 0 then 
  1431.       begin
  1432.          DT1 := (DT2-DT1);
  1433.          if DT1 < 0 then DT1 := DT1+60; {adjust for hour rollover}
  1434.          DosTime := DosTime+DT1;
  1435.       end;
  1436.       inc(DosTimes);
  1437.    end;
  1438.  
  1439.  
  1440. (* -------------------------------------------------------- *)
  1441. procedure sysop_chat;
  1442.  
  1443.    var
  1444.       DT1, DT2 : integer;
  1445.       a: integer;
  1446.       node: boolean;
  1447.  
  1448.    begin
  1449.       node := (inrec[7] = 'N');
  1450.  
  1451.       val(copy(Inrec, 34, 2), DT1, a); {chat started time time}
  1452.       getrec;
  1453.  
  1454.       val(copy(Inrec, 27, 2), DT2, a); {chat ended time}
  1455.       if a = 0 then 
  1456.       begin
  1457.          DT1 := (DT2-DT1);
  1458.          if DT1 < 0 then DT1 := DT1+60; {adjust for hour rollover}
  1459.          if node then
  1460.             mins_nchat := mins_nchat + DT1
  1461.          else
  1462.             mins_schat := mins_schat + DT1;
  1463.       end;
  1464.  
  1465.       if node then
  1466.          inc(nchat)
  1467.       else
  1468.          inc(schat);
  1469.    end;
  1470.  
  1471.  
  1472. (* -------------------------------------------------------- *)
  1473. procedure catchall;
  1474.    begin
  1475.       if pos(' CHAT ', Inrec) > 0 then sysop_chat
  1476.       else if pos('Access Denied', Inrec) > 0 then inc(tcan)
  1477.       else if pos('Comment ', Inrec) > 0 then inc(comments)
  1478.       else if pos(' DOOR ', Inrec) > 0 then pdoors
  1479.       else if pos('Left:', Inrec) > 0 then inc(mssgs)
  1480.       else if pos('not registered', Inrec) > 0 then inc(secviol)
  1481.       else if pos('ock-', Inrec) > 0 then inc(lockouts)
  1482.       else if pos('oined', Inrec) > 0 then confjoin
  1483.       else if pos('Paged', Inrec) > 0 then inc(PAGE)
  1484.       else if pos('Questionnaire ', Inrec) > 0 then inc(question)
  1485.       else if pos('Refused', Inrec) > 0 then inc(refused)
  1486.       else if pos('Scheduled', Inrec) > 0 then inc(events)
  1487.       else if pos('Time Limit', Inrec) > 0 then inc(time_limit)
  1488.       else if pos('Violation', Inrec) > 0 then inc(secviol)
  1489.    end;
  1490.  
  1491.  
  1492. (* -------------------------------------------------------- *)
  1493. procedure scanfile;
  1494.  
  1495.    var
  1496.       tx1 : string[20];
  1497.       a, y, p : integer;
  1498.       minutoff,
  1499.       houroff,
  1500.       timeused : integer;
  1501.       lastx : word;
  1502.  
  1503.    begin
  1504.       lastx := total_records;
  1505.       total_records := first_record;
  1506.  
  1507.       while (total_records <= lastx) do
  1508.       begin
  1509.          if total_records mod 30 = 1 then
  1510.          begin
  1511.             str((int(total_records)/int(logsize)*100.0) : 5 : 1, tx1);
  1512.             tx1 := 'Working.... '+tx1+' %';
  1513.             print(3, 17, tx1, 12);
  1514.          end;
  1515.  
  1516.          inc(total_records);
  1517.          bseek(DiskFile, total_records);
  1518.          getrec;
  1519.  
  1520.          if pos(') (', Inrec) <> 0 then
  1521.             incaller
  1522.          else
  1523.  
  1524.             if (pos('Minutes Used', Inrec) > 0) then
  1525.             begin
  1526.                p := pos(':', Inrec)+2;
  1527.                y := p;
  1528.                while (Inrec[y] >= '0') and (Inrec[y] <= '9') do
  1529.                   inc(y);
  1530.                val(copy(Inrec, p, y-p), timeused, a);
  1531.  
  1532.                getrec;
  1533.                val(copy(Inrec, 11, 2), houroff, a);
  1534.                if houroff > 23 then
  1535.                   houroff := houroff - 24;
  1536.                val(copy(Inrec, 14, 2), minutoff, a);
  1537.  
  1538.                while timeused > 0 do
  1539.                   begin
  1540.                      if timeused > minutoff then
  1541.                         a := minutoff
  1542.                      else
  1543.                         a := timeused;
  1544.  
  1545.                      UsedMinutes := UsedMinutes + a;
  1546.                      while UsedMinutes > 60 do
  1547.                      begin
  1548.                         inc(Hours);
  1549.                         UsedMinutes := UsedMinutes - 60;
  1550.                      end;
  1551.  
  1552.                      Hrs[houroff] := Hrs[houroff]+a;
  1553.                      timeused := timeused-a;
  1554.  
  1555.                      if houroff > 0 then
  1556.                         dec(houroff)
  1557.                      else
  1558.                         houroff := 23;
  1559.                      minutoff := 60;
  1560.                   end;
  1561.             end
  1562.  
  1563.          else
  1564.             case Inrec[7] of
  1565.                '*' :;
  1566.  
  1567.                '(' : if inrec[9] <> ')' then inc(stuff)
  1568.                      else if inrec[8] = 'D' then indownload
  1569.                      else if inrec[8] = 'U' then indownload
  1570.                      else catchall;
  1571.  
  1572.                'A' : if pos('Access Denied', Inrec) > 0 then inc(tcan)
  1573.                      else if pos('ARC view', Inrec) > 0 then inc(arcview)
  1574.                      else if pos('Archive view', Inrec) > 0 then inc(arcview)
  1575.                      else if pos('ARC test', Inrec) > 0 then inc(arctest)
  1576.                      else if pos('ARCM exe', Inrec) > 0 then inc(arcmail)
  1577.                      else catchall;
  1578.  
  1579.                'B' : if pos('Bulletin Read:', Inrec) > 0 then bulletins
  1580.                      else if pos('Back from DOS', Inrec) > 0 then inc(backdos)
  1581.                      else catchall;
  1582.  
  1583.                'C' : if pos('Comment ', Inrec) > 0 then inc(comments)
  1584.                      else if pos('Caller Exited to DOS ', Inrec) > 0 then DOSdrop
  1585.                      else catchall;
  1586.  
  1587.                'D' : if pos('Directory Scan ', Inrec) > 0 then inc(dirscan)
  1588.                      else catchall;
  1589.  
  1590.                'E' : if pos('Extract ', Inrec) > 0 then inc(extarc)
  1591.                      else catchall;
  1592.  
  1593.                'F' : if pos('File (', Inrec) > 0 then inc(stuff)
  1594.                      else if pos('Free download', Inrec) > 0 then inc(free_down)
  1595.                      else catchall;
  1596.  
  1597.                'K' : if pos('Keyboard Time',Inrec) > 0 then inc(stuff)
  1598.                      else catchall;
  1599.  
  1600.                'I':  if pos('Insufficient ',Inrec) > 0 then inc(secviol)
  1601.                      else if pos('Invalid archive',Inrec) > 0 then inc(invalids)
  1602.                      else catchall;
  1603.  
  1604.                'M' : if pos('Left:', Inrec) > 0 then inc(mssgs)
  1605.                      else if pos('Killed:', Inrec) > 0 then inc(kills)
  1606.                      else catchall;
  1607.  
  1608.                'N' : if pos('Node CHAT ent', Inrec) > 0 then sysop_chat
  1609.                      else if pos('Node CHAT end', Inrec) > 0 then inc(stuff)
  1610.                      else catchall;
  1611.  
  1612.                'O' : if pos('Operator', Inrec) > 0 then inc(PAGE)
  1613.                      else if pos(' DOOR ', Inrec) > 0 then pdoors
  1614.                      else catchall;
  1615.  
  1616.                'P' : if pos('Password Failure (', Inrec) > 0 then inc(pwfail)
  1617.                      else if pos('PAKM exe', Inrec) > 0 then inc(arcmail)
  1618.                      else catchall;
  1619.  
  1620.                'R' : if pos('Refused', Inrec) > 0 then inc(refused)
  1621.                      else if pos('Registration', Inrec) > 0 then inc(new_guys)
  1622.                      else if pos('REARC ', Inrec) > 0 then inc(rearcs)
  1623.                      else if pos('REPAK ', Inrec) > 0 then inc(rearcs)
  1624.                      else catchall;
  1625.  
  1626.                'S' : if pos('Scheduled', Inrec) > 0 then inc(events)
  1627.                      else if pos('Sorry', Inrec) > 0 then inc(secviol)
  1628.                      else if pos('Sysop CHAT a', Inrec) > 0 then sysop_chat
  1629.                      else if pos('Sysop CHAT e', Inrec) > 0 then inc(stuff)
  1630.                      else catchall;
  1631.  
  1632.                'T' : if pos('Time Limit', Inrec) > 0 then inc(time_limit)
  1633.                      else if pos('TEST executed', Inrec) > 0 then inc(arctest)
  1634.                      else if pos('Thanks, ', Inrec) > 0 then inc(secviol)
  1635.                      else catchall;
  1636.  
  1637.                'V' : if pos('View ARC', Inrec) > 0 then inc(viewmember)
  1638.                      else if pos('View archive', Inrec) > 0 then inc(viewmember)
  1639.                      else catchall;
  1640.  
  1641.                '0'..'9':
  1642.                      if pos(' files,',Inrec) > 0 then batch
  1643.                      else if pos(' messages ',Inrec) > 0 then arcmsgs
  1644.                      else catchall;
  1645.  
  1646.             else catchall;
  1647.             end;
  1648.       end;
  1649.  
  1650.       tx1 := 'Working.... 100.0 %';
  1651.       print(3, 17, tx1, 12);
  1652.    end;
  1653.  
  1654.  
  1655. (* -------------------------------------------------------- *)
  1656.  
  1657. var
  1658.    line: string;
  1659.    xfd: text;
  1660.  
  1661. procedure write_list(node: ItemPointer);
  1662. begin
  1663.    while node <> nil do
  1664.    begin
  1665.       writeln(xfd,node^.name);
  1666.       writeln(xfd,node^.count);
  1667.       node := node^.next;
  1668.    end;
  1669.    writeln(xfd);
  1670. end;
  1671.  
  1672. procedure write_tree(node: FilePointer);
  1673. begin
  1674.    if node = nil then
  1675.       writeln(xfd)
  1676.    else
  1677.    begin
  1678.       writeln(xfd,node^.name);
  1679.       writeln(xfd,node^.size,' ',node^.count);
  1680.       write_tree(node^.higher);
  1681.       write_tree(node^.lower);
  1682.    end;
  1683. end;
  1684.  
  1685.  
  1686. (* -------------------------------------------------------- *)
  1687.  
  1688. procedure read_list(var node: ItemPointer);
  1689. var
  1690.    add:  ItemPointer;
  1691.  
  1692. begin
  1693.    {special case - empty list}
  1694.    readln(xfd,line);
  1695.    if length(line) = 0 then
  1696.    begin
  1697.       node := nil;
  1698.       exit;
  1699.    end;
  1700.  
  1701.    {insert head of list}
  1702.    new(node);
  1703.    add := node;
  1704.    add^.name := line;
  1705.    readln(xfd,add^.count);
  1706.  
  1707.    {add rest of the list}
  1708.    readln(xfd,line);
  1709.    while length(line) <> 0 do
  1710.    begin
  1711.       new(add^.next);
  1712.       add := add^.next;
  1713.       add^.name := line;
  1714.       readln(xfd,add^.count);
  1715.  
  1716.       readln(xfd,line);
  1717.    end;
  1718.  
  1719.    add^.next := nil;
  1720. end;
  1721.  
  1722.  
  1723. procedure read_tree(var node: FilePointer);
  1724. begin
  1725.    readln(xfd,line);
  1726.    if length(line)=0 then
  1727.       node := nil
  1728.    else
  1729.    begin
  1730.       new(node);
  1731.       node^.name := line;
  1732.       read(xfd,node^.size);
  1733.       readln(xfd,node^.count);
  1734.       read_tree(node^.higher);
  1735.       read_tree(node^.lower);
  1736.    end;
  1737. end;
  1738.  
  1739.  
  1740. (* -------------------------------------------------------- *)
  1741. procedure save_state;
  1742. var
  1743.    i: integer;
  1744.  
  1745. begin
  1746.    gotoxy(1, 1);
  1747.    write('Writing CALLS.SAV...');
  1748.  
  1749.    assign(xfd,'calls.sav');
  1750.    rewrite(xfd);
  1751.  
  1752.    writeln(xfd,'-4');
  1753.    writeln(xfd,
  1754.            spare1,' ',  spare2,' ',
  1755.            spare3,' ',  spare4,' ',
  1756.            spare5,' ',  spare6,' ',
  1757.            spare7,' ',  spare8,' ',
  1758.            spare9,' ',  B4800);
  1759.    writeln(xfd,
  1760.            arcmail,' ', msgcount,' ',
  1761.            invalids,' ',mins_dn,' ',
  1762.            mins_up,' ', mins_schat,' ',
  1763.            nchat,' ',   mins_nchat,' ',
  1764.            arctest,' ', free_down);
  1765.    writeln(xfd,
  1766.            arcview,' ',      B1200,' ',
  1767.            B19200,' ',       B2400,' ',
  1768.            B300,' ',         B9600,' ',
  1769.            backdos,' ',      batchs);
  1770.    writeln(xfd,
  1771.            Blocal,' ',       blts,' ',
  1772.            caller,' ',       schat,' ',
  1773.            comments,' ',     dirscan,' ',
  1774.            DOORs,' ',        DosTime);
  1775.    writeln(xfd,
  1776.            DosTimes,' ',     down,' ',
  1777.            d_abort,' ',      events,' ',
  1778.            even_parity,' ',  extarc,' ',
  1779.            graphics,' ',     Hours);
  1780.    writeln(xfd,
  1781.            joins,' ',        kills,' ',
  1782.            lockouts,' ',     UsedMinutes,' ',
  1783.            mssgs,' ',        new_guys,' ',
  1784.            non_graphics,' ', PAGE);
  1785.    writeln(xfd,
  1786.            pwfail,' ',       question,' ',
  1787.            rearcs,' ',       refused,' ',
  1788.            secviol,' ',      stuff,' ',
  1789.            sysop_local,' ',  sysop_remote);
  1790.    writeln(xfd,
  1791.            tcan,' ',         time_limit,' ',
  1792.            TotHours:0:2,' ', UniqFiles,' ',
  1793.            up,' ',           u_abort,' ',
  1794.            viewmember);
  1795.  
  1796.    writeln(xfd,copy(first_rec,1,62));
  1797.  
  1798.    for i := 1 to ProtocolCount do
  1799.    with Protocol[i] do
  1800.       writeln(xfd,
  1801.                  code,' ',
  1802.                  Uploads,' ',
  1803.                  UpTime:0:2,' ',
  1804.                  UpIdeal:0:2,' ',
  1805.                  Downloads,' ',
  1806.                  DownTime:0:2,' ',
  1807.                  DownIdeal:0:2);
  1808.  
  1809.    for i := 0 to 23 do
  1810.       writeln(xfd,Hrs[i]);
  1811.  
  1812.    write_list(FirstBatch);
  1813.    write_list(FirstBullet);
  1814.    write_list(FirstConf);
  1815.    write_list(FirstDoor);
  1816.    write_tree(FileTree);
  1817.  
  1818.    close(xfd);
  1819.    writeln(^M'                        ');
  1820. end;
  1821.  
  1822.  
  1823. (* -------------------------------------------------------- *)
  1824. procedure load_state;
  1825. var
  1826.    i: integer;
  1827.    c: char;
  1828.  
  1829. begin
  1830.    assign(xfd,'calls.sav');
  1831.    {$i-} reset(xfd); {$i+}
  1832.    if ioresult <> 0 then
  1833.       exit;
  1834.  
  1835.    gotoxy(1, 1);
  1836.    writeln('Loading CALLS.SAV...');
  1837.  
  1838.    read(xfd,filever);
  1839.    if filever <> -4 then
  1840.    begin
  1841.       writeln('Can''t use your old CALLS.SAV file!  Will create a new one.');
  1842.       close(xfd);
  1843.       exit;
  1844.    end;
  1845.  
  1846.    read(xfd,
  1847.            spare1,      spare2,
  1848.            spare3,      spare4,
  1849.            spare5,      spare6,
  1850.            spare7,      spare8,
  1851.            spare9,      B4800);
  1852.    read(xfd,
  1853.            arcmail,     msgcount,
  1854.            invalids,    mins_dn,
  1855.            mins_up,     mins_schat,
  1856.            nchat,       mins_nchat,
  1857.            arctest,     free_down);
  1858.    read(xfd,
  1859.            arcview,      B1200,
  1860.            B19200,       B2400,
  1861.            B300,         B9600,
  1862.            backdos,      batchs);
  1863.    read(xfd,
  1864.            Blocal,       blts,
  1865.            caller,       schat,
  1866.            comments,     dirscan,
  1867.            DOORs,        DosTime);
  1868.    read(xfd,
  1869.            DosTimes,     down,
  1870.            d_abort,      events,
  1871.            even_parity,  extarc,
  1872.            graphics,     Hours);
  1873.    read(xfd,
  1874.            joins,        kills,
  1875.            lockouts,     UsedMinutes,
  1876.            mssgs,        new_guys,
  1877.            non_graphics, PAGE);
  1878.    read(xfd,
  1879.            pwfail,       question,
  1880.            rearcs,       refused,
  1881.            secviol,      stuff,
  1882.            sysop_local,  sysop_remote);
  1883.    readln(xfd,
  1884.            tcan,         time_limit,
  1885.            TotHours,     UniqFiles,
  1886.            up,           u_abort,
  1887.            viewmember);
  1888.  
  1889.    readln(xfd,first_rec);
  1890.  
  1891.    repeat
  1892.       read(xfd,c);
  1893.  
  1894.       i := 1;
  1895.       while (i < ProtocolCount) and 
  1896.             (c <> Protocol[i].Code) and
  1897.             (Protocol[i].Code <> '?') do
  1898.          inc(i);
  1899.  
  1900.       with Protocol[i] do
  1901.          readln(xfd,Uploads,
  1902.                     UpTime,
  1903.                     UpIdeal,
  1904.                     Downloads,
  1905.                     DownTime,
  1906.                     DownIdeal);
  1907.    until c = '?';
  1908.  
  1909.    for i := 0 to 23 do
  1910.       readln(xfd,Hrs[i]);
  1911.  
  1912.    read_list(FirstBatch);
  1913.    read_list(FirstBullet);
  1914.    read_list(FirstConf);
  1915.    read_list(FirstDoor);
  1916.    read_tree(FileTree);
  1917.  
  1918.    close(xfd);
  1919.    writeln(^M'                        ');
  1920. end;
  1921.  
  1922.  
  1923.  
  1924. (* -------------------------------------------------------- *)
  1925.  
  1926. procedure load_dirs;
  1927. var
  1928.    fd:   text;
  1929.  
  1930. begin
  1931.    search_dirs := 0;
  1932. (***
  1933.    assign(fd,'calls.dir');
  1934.    {$i-} reset(fd); {$i+}
  1935.    if ioresult <> 0 then
  1936.    begin
  1937.       writeln('Warning: CALLS.DIR is missing.');
  1938.       exit;
  1939.    end;
  1940.  
  1941.    while not eof(fd) do
  1942.    begin
  1943.       inc(search_dirs);
  1944.       readln(fd,search_dir[search_dirs]);
  1945.    end;
  1946.  
  1947.    close(fd);
  1948. ***)
  1949. end;
  1950.  
  1951. (* -------------------------------------------------------- *)
  1952.  
  1953. procedure init;            {initialize}
  1954.  
  1955.    begin
  1956.       {Initialize the variables}
  1957.       total_records := 0;
  1958.       first_record := 0;
  1959.       viewmember := 0;
  1960.       extarc := 0;
  1961.       rearcs := 0;
  1962.       arctest := 0;
  1963.       arcview := 0;
  1964.       B1200 := 0;
  1965.       B19200 := 0;
  1966.       B2400 := 0;
  1967.       B300 := 0;
  1968.       B9600 := 0;
  1969.       backdos := 0;
  1970.       batchs := 0;
  1971.       baud := 0;
  1972.       Blocal := 0;
  1973.       blts := 0;
  1974.       caller := 0;
  1975.       schat := 0;
  1976.       comments := 0;
  1977.       dirscan := 0;
  1978.       DOORs := 0;
  1979.       DosTime := 0;
  1980.       DosTimes := 0;
  1981.       down := 0;
  1982.       d_abort := 0;
  1983.       elapsed_time := 0;
  1984.       Endtime := 0;
  1985.       events := 0;
  1986.       even_parity := 0;
  1987.       free_down := 0;
  1988.       graphics := 0;
  1989.       Hours := 0;
  1990.       joins := 0;
  1991.       kills := 0;
  1992.       lockouts := 0;
  1993.       logsize := 0;
  1994.       UsedMinutes := 0;
  1995.       mssgs := 0;
  1996.       new_guys := 0;
  1997.       non_graphics := 0;
  1998.       PAGE := 0;
  1999.       pwfail := 0;
  2000.       question := 0;
  2001.       refused := 0;
  2002.       secviol := 0;
  2003.       start_time := 0;
  2004.       stuff := 0;
  2005.       sysop_local := 0;
  2006.       sysop_remote := 0;
  2007.       tcan := 0;
  2008.       time_limit := 0;
  2009.       TotHours := 0;
  2010.       UniqFiles := 0;
  2011.       up := 0;
  2012.       u_abort := 0;
  2013.       min_download := 0;
  2014.       msgcount := 0;
  2015.       arcmail := 0;
  2016.       invalids := 0;
  2017.       mins_dn := 0;
  2018.       mins_up := 0;
  2019.       mins_schat := 0;
  2020.       nchat := 0;
  2021.       mins_nchat := 0;
  2022.       spare1 := 0; spare2 := 0; spare3 := 0; spare4 := 0; spare5 := 0;
  2023.       spare6 := 0; spare7 := 0; spare8 := 0; spare9 := 0; B4800 := 0;
  2024.  
  2025.       PeriodCovered := '';
  2026.       reports := '';
  2027.       first_rec := '';
  2028.  
  2029.       FileTree := nil;
  2030.       FirstBatch := nil;
  2031.       FirstBullet := nil;
  2032.       FirstConf := nil;
  2033.       FirstDoor := nil;
  2034.  
  2035.       fillchar(Hrs, sizeof(Hrs), 0);
  2036.       elapsed_time := 0;
  2037.       start_time := Time;
  2038.  
  2039.  
  2040.       {provide command-line defaults}
  2041.       outfile := 'BLT99';
  2042.       reports := 'ANBCDEFGHIJKLM';
  2043.       min_download := 2;
  2044.                    {          1         2   }
  2045.                    {012345678901234567890123}
  2046.       PeakTable := 'YNNNNNNNNNNNNNNNNYYYYYYY';
  2047.  
  2048.       if paramcount < 1 then
  2049.          begin
  2050.             assign(output,'');   {make redirection work so the usage}
  2051.             rewrite(output);     {can be captured in a file}
  2052.  
  2053.             writeln;
  2054.             writeln('Usage:    calls callers-file output-file report-list min-downloads peak-hours');
  2055.             writeln;
  2056.             writeln('callers-file is your pcboard CALLER file');
  2057.             writeln('output-file  defaults to ',outfile);
  2058.             writeln('report-list  defaults to ',reports);
  2059.             writeln('min-download defaults to ',min_download);
  2060.             writeln;
  2061.             writeln('peak-hours   defaults to ',PeakTable);
  2062.             writeln('                        {0         1         2   }');
  2063.             writeln('                        {012345678901234567890123}');
  2064.             writeln('Examples:');
  2065.             writeln('  calls \pcb\main\caller \gen\blt3');
  2066.             writeln('  calls \pcb\main\caller \gen\blt3 ABCEFG 4 NNNNNNNNYYYYYYYYYNNNNNNN');
  2067.             writeln;
  2068.             writeln('The legal report-list letters are:');
  2069.             writeln('   A: system statistics            B: graphic modes');
  2070.             writeln('   C: baud rates                   D: hourly usage');
  2071.             writeln('   E: conferences joined           F: bulletins read');
  2072.             writeln('   G: doors opened                 H: download protocols');
  2073.             writeln('   I: download efficiency          J: upload protocols');
  2074.             writeln('   K: upload efficiency            L: batch sizes');
  2075.             writeln('   M: files downloaded             N: security statistics');
  2076.             writeln('                                   Z: insert a blank line');
  2077.             halt;
  2078.          end;
  2079.  
  2080.       if paramcount > 1 then
  2081.          outfile := paramstr(2);
  2082.       if paramcount > 2 then
  2083.          reports := paramstr(3);
  2084.       if paramcount > 3 then
  2085.          val(paramstr(4),min_download,total_records);
  2086.       if paramcount > 4 then
  2087.          PeakTable := paramstr(5);
  2088.  
  2089.       clrscr;
  2090.       print(13,  5, '╔═════════════════════════════════════════════════════╗', lightred);
  2091.       print(13,  6, '║                                                     ║', lightred);
  2092.       print(13,  7, '║                                                     ║', lightred);
  2093.       print(13,  8, '║                                                     ║', lightred);
  2094.       print(13,  9, '║                                                     ║', lightred);
  2095.       print(13, 10, '║                                                     ║', lightred);
  2096.       print(13, 11, '║                                                     ║', lightred);
  2097.       print(13, 12, '║                                                     ║', lightred);
  2098.       print(13, 13, '║                                                     ║', lightred);
  2099.       print(13, 14, '║                                                     ║', lightred);
  2100.       print(13, 15, '╚═════════════════════════════════════════════════════╝', lightred);
  2101.  
  2102.       print(32, 7, pcbversion, lightgreen);
  2103.       print(30, 9, 'Calls v'+version+', '+reldate, lightgreen);
  2104.       print(29, 11, '(c) 1987  Warren Lauzon', lightcyan);
  2105.       print(20, 13, 'Supported by The Tool Shop, 602/279-2673', crt.white);
  2106.       gotoxy(1,1);
  2107.    end;
  2108.  
  2109.  
  2110. (* -------------------------------------------------------- *)
  2111. begin
  2112.    init;
  2113.    load_state;
  2114.    load_dirs;
  2115.    openfiles;
  2116.    scanfile;
  2117.  
  2118.    Endtime := Time;
  2119.    elapsed_time := Endtime-start_time;
  2120.    gotoxy(30, 17);
  2121.    writeln('Elapsed Time:  ', elapsed_time : 6 : 1);
  2122.  
  2123.    output_results(outfile+'G');
  2124.  
  2125.    red := '';
  2126.    green := '';
  2127.    yellow := '';
  2128.    blue := '';
  2129.    magenta := '';
  2130.    cyan := '';
  2131.    white := '';
  2132.    gray := '';
  2133.    output_results(outfile);
  2134.  
  2135.    save_state;
  2136.    gotoxy(1, 25);
  2137. end.
  2138.  
  2139.